/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package it.txt.access.capability.finder.util;

import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

/**
 *
 * @author seccia
 */
public class URIResourceIDRegexCreator {

    //Java Regex Special chars: "([{\^-$|]})?*+."
    private static final Logger LOGGER = Logger.getLogger(URIResourceIDRegexCreator.class.getName());
    //public static final String defaultPath = "D:/Developing/URIResourceIDMatch.txt";
    public static final String REGEX_SCHEMA = "([^:/?#]+)";
    public static final String REGEX_AUTHORITY = "([^/?#:]*)";
    public static final String REGEX_SERVICE = "([^?#/]*)";
    public static final String REGEX_NAMESPACE = "([^&]*)";
    public static final String REGEX_TOPIC = REGEX_NAMESPACE;
    public static final String REGEX_DOT = "\\.";
    public static final String REGEX_SLASH = "\\";
    private static final String REGEX_WILD = "[#\\*]";
    public static final String REGEX_CHARS = "([\\w\\-\\s_%\\d]+)";
    public static final String REGEX_CHARS_OR_STAR = ""
            + "("
            + REGEX_CHARS
            + "|"
            + "(\\*)"
            + ")";
    public static final String REGEX_CHARS_OR_WILD = ""
            + "("
            + REGEX_CHARS
            + "|"
            + REGEX_WILD
            + ")";
    public static final String SPECIAL_CHARS_REGEX = ""
            + "[" + REGEX_SLASH + "(" + REGEX_SLASH + "["
            + REGEX_SLASH + "{" + REGEX_SLASH + "\\"
            + REGEX_SLASH + "^" + REGEX_SLASH + "-"
            + REGEX_SLASH + "$" + REGEX_SLASH + "|"
            + REGEX_SLASH + "]" + REGEX_SLASH + "}"
            + REGEX_SLASH + ")" + REGEX_SLASH + "?"
            + REGEX_SLASH + "+" + REGEX_SLASH + "." + "]";
    public static final String CAPABILITY_URI_REGEX = ""
            + "^"
            + REGEX_SCHEMA
            + "://"
            + REGEX_AUTHORITY
            + "/"
            + REGEX_SERVICE
            + "\\?" + "Namespace="
            + REGEX_NAMESPACE
            + "&" + "Pattern="
            + REGEX_TOPIC
            + "$";
    public static final String PATTERN_APPEND_REGEX = ""
            + "(" + REGEX_DOT + REGEX_CHARS_OR_WILD + ")*";
    public static final String PATTERN_REGEX = ""
            + REGEX_CHARS_OR_WILD + PATTERN_APPEND_REGEX;

    public static String recoverResourceIDRegex(String resourceID) {

        Pattern uriPattern = Pattern.compile(CAPABILITY_URI_REGEX, Pattern.CASE_INSENSITIVE);
        Matcher resourceIDURIRegexMatcher = uriPattern.matcher(resourceID);

        if (resourceIDURIRegexMatcher.matches()) {
            URIResourceIDSections sections = new URIResourceIDSections();
            String resourceIDSchema = resourceIDURIRegexMatcher.group(1);
            sections.setScheme(resourceIDSchema);
            String resourceIDAuthority = resourceIDURIRegexMatcher.group(2);
            sections.setAuthority(resourceIDAuthority);
            String resourceIDService = resourceIDURIRegexMatcher.group(3);
            sections.setService(resourceIDService);
            String resourceIDNamespace = resourceIDURIRegexMatcher.group(4);
            sections.setNamespace(resourceIDNamespace);
            String resourceIDPattern = resourceIDURIRegexMatcher.group(5);
            sections.setPattern(resourceIDPattern);
            String resourceIDregex = recoverResourceIDPatternRegex(sections);
            String print =  "\n-------------------------------\n"
                            + "Resource URI content::" + "\n"
                            + "  . ResourceID: " + resourceID + "\n"
                            + "  . ResourceID-Schema: " + resourceIDSchema + "\n"
                            + "  . ResourceID-Authority: " + resourceIDAuthority + "\n"
                            + "  . ResourceID-Service: " + resourceIDService + "\n"
                            + "  . ResourceID-Namespace: " + resourceIDNamespace + "\n"
                            + "  . ResourceID-Pattern: " + resourceIDPattern + "\n"
                            + "  . ResourceID-Regex: " + resourceIDregex + "\n";
            if (regularExpressionTest(resourceIDregex, resourceID)) {
                print += "  . Testing the given resource URI against the recovered regex - OK" + "\n";
            } else {
                print += "  . Testing the given resource URI against the recovered regex - ERROR" + "\n";
            }
            print += "-------------------------------";
            LOGGER.log(Level.INFO, print);
            return resourceIDregex;
        }
        return null;
    }

    private static String recoverResourceIDPatternRegex(URIResourceIDSections sections) {
        String pattern = sections.getPattern();
        String[] items = pattern.split("\\.");
        //The start of the regular expression
        String patternRegex = "";
        //The dots / nodes counter
        int dots = 0;
        //appen or not the last pattern regex section.
        boolean escape = false;
        //For each item / node in the resource ID / tree
        for (String item : items) {
            //In this case the char "*" means a node in the tree, it
            //can be replaced by the regex REGEX_CHARS.
            if (item.equals("*")) {
                patternRegex += REGEX_CHARS_OR_STAR;
                //Escape the REGEX_APPEND if the "*" is the last item.
                if (dots == items.length - 1) {
                    escape = true;
                }
            } //In this case the char "#" means one or more nodes in the tree,
            //it can be replaced by the regex REGEX_RESOURCE_ID.
            else if (item.equals("#") || item.equals("%23")) {
                patternRegex += PATTERN_REGEX;
                //Escape the REGEX_APPEND if the "#" is the last item.
                if (dots == items.length - 1) {
                    escape = true;
                }
            } else {
                //append the current item to the overall regex
                //after raplacing the special characters with the escape
                patternRegex += replaceSpecialChars(item);
            }
            //Append the char "." to the regex
            if (dots != items.length - 1) {
                patternRegex += REGEX_DOT;
            }
            dots++;
        }
        //If the current item is not a "*" or a "#" then append
        //to the regex REGEX_APPEND
        if (!escape) {
            patternRegex += PATTERN_APPEND_REGEX;
        }

        String schema = replaceSpecialChars(sections.getScheme());
        String authority = replaceSpecialChars(sections.getAuthority());
        String service = replaceSpecialChars(sections.getService());
        String namespace = replaceSpecialChars(sections.getNamespace());

        return "^"
                + schema
                + "://"
                + authority
                + "/"
                + service
                + "\\?"
                + "Namespace="
                + namespace
                + "&"
                + "Pattern="
                + patternRegex + "$";
    }

    public static boolean regularExpressionTest(String expression, String value) {
        Pattern resourceIDRegexPatternTest = Pattern.compile(expression,
                Pattern.CASE_INSENSITIVE);
        Matcher topicPatternVSResourceIDPattern =
                resourceIDRegexPatternTest.matcher(value);
        return topicPatternVSResourceIDPattern.matches();
    }

    private static String replaceSpecialChars(final String item) {
        String result = item;
        Pattern specialCharsPattern = Pattern.compile(SPECIAL_CHARS_REGEX);
        //Find any special character in the current item.
        //replace by adding the escape char "\" in order to
        //be part of a valid regular expression.
        Matcher matcher = specialCharsPattern.matcher(item);
        while (matcher.find()) {
            String special = matcher.group();
            result = item.replace(special, REGEX_SLASH + special);
        }
        return result;
    }

    /*public static void main(String[] args) throws Exception {

    ArrayList<MatchTest> mts = MatchTestHelper.readMatchTestFromFile(defaultPath);

    System.out.println("***********************************");
    for (MatchTest mt : mts) {
    String topic = mt.getTopic();
    String resourceID = mt.getResourceID();
    System.out.println("Macht Test");
    System.out.println("-------------------------------");
    System.out.println(". Topic: \"" + topic + "\"");
    System.out.println(". Resource ID: \"" + resourceID + "\"");
    System.out.println("-------------------------------");
    Pattern uriPattern = Pattern.compile(CAPABILITY_URI_REGEX, Pattern.CASE_INSENSITIVE);
    Matcher resourceIDURIRegexMatcher = uriPattern.matcher(resourceID);
    if (resourceIDURIRegexMatcher.matches()) {
    //groups include also the entire string
    //for (int i = 0; i < resourceIDURIRegexMatcher.groupCount() + 1; i++) {
    //String group = resourceIDURIRegexMatcher.group(i);
    //System.out.println(". ResourceID 's Group(" + i + "): " + group);
    //System.out.println("-----------------------------");
    //}
    System.out.println(". URI Regex - ResourceID Match OK");
    System.out.println("-------------------------------");
    String resourceIDSchema = resourceIDURIRegexMatcher.group(1);
    System.out.println("  . ResourceID-Schema: " + resourceIDSchema);
    String resourceIDAuthority = resourceIDURIRegexMatcher.group(2);
    System.out.println("  . ResourceID-Authority: " + resourceIDAuthority);
    String resourceIDService = resourceIDURIRegexMatcher.group(3);
    System.out.println("  . ResourceID-Service: " + resourceIDService);
    String resourceIDNamespace = resourceIDURIRegexMatcher.group(4);
    System.out.println("  . ResourceID-Namespace: " + resourceIDNamespace);
    String resourceIDPattern = resourceIDURIRegexMatcher.group(5);
    System.out.println("  . ResourceID-Pattern: [" + resourceIDPattern + "]");
    //recover the pattern 's regex
    String resourceIDPatternRegex = recoverResourceIDPatternRegex(resourceIDPattern);
    System.out.println("  . ResourceID-Pattern 's Regex: " + resourceIDPatternRegex);
    System.out.println("-------------------------------");
    Matcher topicURIRegexMatcher = uriPattern.matcher(topic);
    if (topicURIRegexMatcher.matches()) {
    System.out.println(". URI Regex - Tpic Match OK");
    System.out.println("-------------------------------");
    String topicSchema = topicURIRegexMatcher.group(1);
    System.out.println("  . Topic-Schema: " + topicSchema);
    String topicAuthority = topicURIRegexMatcher.group(2);
    System.out.println("  . Topic-Authority: " + topicAuthority);
    String topicService = topicURIRegexMatcher.group(3);
    System.out.println("  . Topic-Service: " + topicService);
    String topicNamespace = topicURIRegexMatcher.group(4);
    System.out.println("  . Topic-Namespace: " + topicNamespace);
    String topicPattern = topicURIRegexMatcher.group(5);
    System.out.println("  . Topic-Pattern: [" + topicPattern + "]");
    Pattern resourceIDPatternPattern =
    Pattern.compile(resourceIDPatternRegex,
    Pattern.CASE_INSENSITIVE);
    Matcher topicPatternVSResourceIDPattern =
    resourceIDPatternPattern.matcher(topicPattern);
    if (topicPatternVSResourceIDPattern.matches()) {
    System.out.println("  . Topic-Pattern vs ResourceID-Pattern - Match OK");
    } else {
    System.out.println("  . Topic-Pattern vs ResourceID-Pattern - Match NO");
    }
    } else {
    System.out.println(". URI Regex - Tpic Match NO");
    }

    } else {
    System.out.println(". URI Regex - ResourceID Match NO");
    }
    System.out.println("***********************************");
    }
    }*/
}
